/******************************************
 *Author:庄育龙
 *Function:开始局域网对战对话框的实现，并有处理UDP数据报的能力
 *Created Date:2013.05.22
 *Last Modified:2013.05.28
 ******************************************/

#include "networkd.h"
#include "ui_networkd.h"
#include "netdialog.h"
#include <QMessageBox>
#include <QSettings>
#include <QUdpSocket>
#include <QTextCodec>

networkd::networkd(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::networkd)
{

    ui->setupUi(this);
    ui->label->hide();
    ui->label_2->hide();
    udpSocket = new QUdpSocket(this);
    port = 45454;
    udpSocket->bind(port,QUdpSocket::ShareAddress
                    | QUdpSocket::ReuseAddressHint);
    //声明UDP Socket及端口

    sendMessage(Allow,0);
    connect(udpSocket,SIGNAL(readyRead()),this,SLOT(processPendingDatagrams()));
    //UDP Socket可以读取数据时连通知槽processPendingDatagrams()以读取UDP数据报
    timer.start(2000);
    connect(&timer,SIGNAL(timeout()),this,SLOT(newserver()));
    //声明一个Timer使得每两秒调用一次newserver槽，使得新建服务器后服务器能够持续广播
}

networkd::~networkd()
{
    delete ui;
}

void networkd::on_pushButton_3_clicked()
{
    sendMessage(ServerLeft);
    //点击退出时发送ServerLeft消息
    close();
}

void networkd::on_pushButton_clicked()//点击新建服务器时的事件
{
    bool ok;
    NetDialog netdialog;//新建对话框对象
    if(netdialog.exec()==QDialog::Accepted) ok=true;
    else ok=false;
    setfile = QApplication::applicationDirPath()+"/settings.ini";
    QSettings settings(setfile, QSettings::IniFormat);
    if(settings.value("First/Server").toInt()) {
        ServerFirst=true;
    }
    else {
        ServerFirst=false;
    }
    if(settings.value("Forbidden/NEnable").toInt()) {
        IsForbidden=true;
    }
    else {
        IsForbidden=false;
    }
    if(settings.value("Undo/Allow").toInt()) {
        AllowUndo=true;
    }
    else {
        AllowUndo=false;
    }
    //以上用来从设置文件中读取设置并调整相应变量
    if(ok) {//确保在新建服务器对话框点击确定时才发送NewServer消息
        sendMessage(NewServer);
        ui->pushButton->setEnabled(0);
        ui->pushButton_2->setEnabled(0);
        //新建完服务器即禁用新建服务器和加入服务器按钮
        ui->label_2->show();
        //显示等待加入者的label
    }
}

void networkd::newserver() {
    if(!ui->pushButton->isEnabled()) {
        //因为新建完服务器后该按钮会被禁用，故只要判断该按钮是否禁用即可判断是否已经新建完服务器
        sendMessage(NewServer);
    }
}

QString networkd::getUserName() {//从设置文件中读取服务器名
    setfile = QApplication::applicationDirPath()+"/settings.ini";
    QSettings settings(setfile, QSettings::IniFormat);
    QByteArray nameBytes=settings.value("Name/ServerName").toByteArray();
    QTextCodec * codec=QTextCodec::codecForName("UTF8");
    QString name=codec->toUnicode(nameBytes);
    if(name[0]!='\0') return name;
    else return "新服务器";
}

QString networkd::getUserID() {//从设置文件中读取玩家名字
    setfile = QApplication::applicationDirPath()+"/settings.ini";
    QSettings settings(setfile, QSettings::IniFormat);
    QByteArray nameBytes=settings.value("Name/Name").toByteArray();
    QTextCodec * codec=QTextCodec::codecForName("UTF8");
    QString name=codec->toUnicode(nameBytes);
    if(name[0]!='\0') return name;
    else return "玩家";
}

QString networkd::getIP() {//获取ip地址
    QList<QHostAddress> list = QNetworkInterface::allAddresses();
    foreach (QHostAddress address, list)
    {
        if(address.protocol() == QAbstractSocket::IPv4Protocol) //使用IPv4地址
            return address.toString();
    }
    return 0;
}

void  networkd::sendMessage(MessageType type, QString serverAddress)  //发送信息
{
    //该函数功能与mainwindow.cpp中的sendMessage()函数功能形式类似
    QByteArray data;
    QDataStream out(&data,QIODevice::WriteOnly);
    QString address = getIP();
    out << type << getUserName();

    switch(type)
    {
    case ServerLeft://服务器离开
    {
        out << address;
        break;
    }

    case NewServer://新服务器
    {
        out << address << ServerFirst << IsForbidden << AllowUndo;
        break;
    }

    case Allow://允许加入
    {
        out << address << serverAddress;
        break;
    }
    case Refuse://拒绝加入
    {
        out << serverAddress;
        break;
    }
    case Join://发出加入请求
    {
        int row = ui->tableWidget->currentRow();
        QString Address = ui->tableWidget->item(row,1)->text();//找到tablewidget中选择项目的IP地址
        out << address << Address << getUserID();
        break;
    }
    }
    udpSocket->writeDatagram(data,data.length(),QHostAddress::Broadcast, port);

}

void networkd::processPendingDatagrams()   //接收数据UDP
{
    //该函数功能与mainwindow.cpp中的processPendingDatagrams()函数功能形式类似
    while(udpSocket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        udpSocket->readDatagram(datagram.data(),datagram.size());
        QDataStream in(&datagram,QIODevice::ReadOnly);
        int messageType;
        in >> messageType;
        QString userName,ipAddress,userID;

        switch(messageType)
        {
        case NewServer:
        {
            in >>userName >>ipAddress >>ServerFirst >> IsForbidden >> AllowUndo;
            if(ipAddress==getIP()) break;//屏蔽本地服务器
            newServer(userName,ipAddress);//处理新服务器请求

            break;
        }
        case ServerLeft:
        {
            in >>userName >> ipAddress;
            serverLeft(userName,ipAddress);//处理服务器离开请求
            break;
        }
        case Allow:
        {
            QString serverAddress;
            in >> userName >> ipAddress >> serverAddress;
            if(serverAddress==getIP()) {
                ui->label->hide();
                newgame(userName,serverAddress,ipAddress,!ServerFirst,IsForbidden,AllowUndo);//发出开始局域网游戏信号
                this->close();//关闭对话框
            }
            break;
        }
        case Refuse:
        {
            in >> userName;
            QString serverAddress;
            in >> serverAddress;
            QString ipAddress = getIP();

            if(ipAddress == serverAddress)//处理拒绝消息
            {
                ui->label->hide();
                QMessageBox::information(NULL, "加入失败","你的加入请求被服务器拒绝了",QMessageBox::Ok,QMessageBox::Ok);
            }
            break;
        }
        case Join:
        {
            QString myaddress;
            in >>userName >> ipAddress >> myaddress >>userID;
            if(myaddress!=getIP()) break;
            ui->label_2->hide();
            QString notify="来自"+ipAddress+"的"+userID+"想要与您进行游戏，是否同意？";
            if(QMessageBox::question(NULL, "有玩家想加入", notify, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)==QMessageBox::Yes) {
                sendMessage(Allow,ipAddress);//同意的话发回允许消息
                newgame(userID,myaddress,ipAddress,ServerFirst,IsForbidden,AllowUndo);//发出开始局域网游戏信号
                this->close();//关闭对话框
            }
            else {
                sendMessage(Refuse,ipAddress);//拒绝的话发回拒绝消息
            }
            break;
        }
        }
    }
}

void networkd::newServer(QString userName, QString ipAddress)
{
    if(ui->tableWidget->findItems(ipAddress,Qt::MatchExactly).isEmpty()) {
        //判断是否有相同的服务器，有的话返回假以过滤掉该消息
        QTableWidgetItem *user = new QTableWidgetItem(userName);
        QTableWidgetItem *ip = new QTableWidgetItem(ipAddress);
        ui->tableWidget->insertRow(0);
        ui->tableWidget->setItem(0,0,user);//第一列插入服务器名
        ui->tableWidget->setItem(0,1,ip);//第二列插入IP地址

        QTableWidgetItem *first;
        if(ServerFirst) first=new QTableWidgetItem("服务器");
        else first=new QTableWidgetItem("客户端");
        ui->tableWidget->setItem(0,2,first);//第三列插入哪边先手

        QTableWidgetItem *forbidden;
        if(IsForbidden) forbidden=new QTableWidgetItem("是");
        else forbidden=new QTableWidgetItem("否");
        ui->tableWidget->setItem(0,3,forbidden);//第四列插入是否禁手

        QTableWidgetItem *undo;
        if(AllowUndo) undo=new QTableWidgetItem("是");
        else undo=new QTableWidgetItem("否");
        ui->tableWidget->setItem(0,4,undo);//第五列插入是否能够悔棋

    }
}

void networkd::serverLeft(QString userName, QString ipAddress)//处理服务器离开消息
{
    int rowNum = ui->tableWidget->findItems(ipAddress,Qt::MatchExactly).first()->row();
    //查找是否有相同的IP，找到并删除该项目
    ui->tableWidget->removeRow(rowNum);
}

void networkd::on_pushButton_2_clicked()//加入服务器按钮按下的事件
{
    if(ui->tableWidget->selectedItems().isEmpty())//如果没有选择服务器则弹出对话框返回错误消息
    {
        QMessageBox::warning(0,tr("选择服务器"),tr("请先从服务器列表中选择要加入的服务器！"),QMessageBox::Ok);
        return;
    }
    sendMessage(Join);//发送加入请求
    ui->label->show();//显示等待回复的label
}
